package com.crazyteam.datasource.config;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

/**
 * @author guoyang
 * @Date 2018-01-09
 * 数据源全局管理Holder
 */
public class DataSourceConfigHolder {

    private static final Map<String, DataSourceConfigHolder> dataSourceConfigMap= new ConcurrentHashMap<>();

    private String masterName;

    private String dataSourceBeanName;
    private String masterDataSourceBeanName;
    private String dynamicSlaveDataSourceBeanName;// 动态备库

    private List<String> slavesDataSourceNames = new ArrayList<>();
    private List<String> slavesDataSourceBeanNames = new ArrayList<>();

    private List<DataSourceConfigHolder> aliasConfig = new ArrayList<>();

    private String transactionManagerBeanName;
    private String slaveTransactionManagerBeanName;

    private String transactionExecutorBeanName;
    private String slaveTransactionExecutorBeanName;

    private String sqlSessionFactoryBeanName;
    private String slaveSqlSessionFactoryBeanName;

    private String mapperScannerBeanName;
    private String slaveMapperScannerBeanName;

    public DataSourceConfigHolder(String masterName){
        if (dataSourceConfigMap.containsKey(masterName)){
            throw new RuntimeException("数据库" + masterName + "重复配置");
        }
        this.masterName = masterName;
        dataSourceBeanName = buildDataSourceBeanName(masterName);
        masterDataSourceBeanName = buildDataSourceBeanName(masterName + "Master");
        transactionManagerBeanName = masterName + "TransactionManager";
        transactionExecutorBeanName = masterName + "TransactionExecutor";
        sqlSessionFactoryBeanName = masterName + "SqlSessionFactory";
        mapperScannerBeanName = masterName + "MapperScanner";

        slaveSqlSessionFactoryBeanName = masterName + "SlaveSqlSessionFactory";
        slaveTransactionManagerBeanName = masterName + "SlaveTransactionManager";
        slaveTransactionExecutorBeanName = masterName + "SlaveTransactionExecutor";
        slaveMapperScannerBeanName = masterName + "SlaveMapperScanner";

        dynamicSlaveDataSourceBeanName = buildDataSourceBeanName(masterName + "DynamicSlave");

        dataSourceConfigMap.put(masterName, this);
    }

    public DataSourceConfigHolder(String masterName, String[] slaves){
        this(masterName);

        Stream.of(slaves).filter(StringUtils::isNotEmpty).forEach((slave) -> {slavesDataSourceNames.add(slave);slavesDataSourceBeanNames.add(buildDataSourceBeanName(slave));});

        if (!CollectionUtils.isEmpty(slavesDataSourceBeanNames)){
            masterDataSourceBeanName = buildDataSourceBeanName(masterName + "Master");
        }
    }

    public DataSourceConfigHolder(String masterName, String[] slaves, String[] aliasNames){
        this(masterName, slaves);
        Stream.of(aliasNames).filter(StringUtils::isNotEmpty).forEach((alias) -> aliasConfig.add(new DataSourceConfigHolder(alias)));
    }

    public static String buildDataSourceBeanName(String dataSourceName){
        return  dataSourceName + "DataSource";
    }



    public String getDataSourceBeanName() {
        return Optional.ofNullable(dataSourceBeanName).orElse(masterDataSourceBeanName);
    }

    public void setDataSourceBeanName(String dataSourceBeanName) {
        this.dataSourceBeanName = dataSourceBeanName;
    }

    public String getMasterDataSourceBeanName() {
        return Optional.ofNullable(masterDataSourceBeanName).orElse(dataSourceBeanName);
    }

    public void setMasterDataSourceBeanName(String masterDataSourceBeanName) {
        this.masterDataSourceBeanName = masterDataSourceBeanName;
    }

    public List<String> getSlavesDataSourceNames() {
        return slavesDataSourceNames;
    }

    public void setSlavesDataSourceNames(List<String> slavesDataSourceNames) {
        this.slavesDataSourceNames = slavesDataSourceNames;
    }

    public List<String> getSlavesDataSourceBeanNames() {
        return slavesDataSourceBeanNames;
    }

    public void setSlavesDataSourceBeanNames(List<String> slavesDataSourceBeanNames) {
        this.slavesDataSourceBeanNames = slavesDataSourceBeanNames;
    }

    public String getTransactionManagerBeanName() {
        return transactionManagerBeanName;
    }

    public void setTransactionManagerBeanName(String transactionManagerBeanName) {
        this.transactionManagerBeanName = transactionManagerBeanName;
    }

    public String getMapperScannerBeanName() {
        return mapperScannerBeanName;
    }

    public void setMapperScannerBeanName(String mapperScannerBeanName) {
        this.mapperScannerBeanName = mapperScannerBeanName;
    }

    public String getMasterName() {
        return masterName;
    }

    public void setMasterName(String masterName) {
        this.masterName = masterName;
    }

    public String getSlaveSqlSessionFactoryBeanName() {
        return slaveSqlSessionFactoryBeanName;
    }

    public void setSlaveSqlSessionFactoryBeanName(String slaveSqlSessionFactoryBeanName) {
        this.slaveSqlSessionFactoryBeanName = slaveSqlSessionFactoryBeanName;
    }

    public String getSqlSessionFactoryBeanName() {
        return sqlSessionFactoryBeanName;
    }

    public void setSqlSessionFactoryBeanName(String sqlSessionFactoryBeanName) {
        this.sqlSessionFactoryBeanName = sqlSessionFactoryBeanName;
    }

    public String getSlaveMapperScannerBeanName() {
        return slaveMapperScannerBeanName;
    }

    public void setSlaveMapperScannerBeanName(String slaveMapperScannerBeanName) {
        this.slaveMapperScannerBeanName = slaveMapperScannerBeanName;
    }

    public List<DataSourceConfigHolder> getAliasConfig() {
        return aliasConfig;
    }

    public void setAliasConfig(List<DataSourceConfigHolder> aliasConfig) {
        this.aliasConfig = aliasConfig;
    }

    public String getDynamicSlaveDataSourceBeanName() {
        return dynamicSlaveDataSourceBeanName;
    }

    public void setDynamicSlaveDataSourceBeanName(String dynamicSlaveDataSourceBeanName) {
        this.dynamicSlaveDataSourceBeanName = dynamicSlaveDataSourceBeanName;
    }

    public String getSlaveTransactionExecutorBeanName() {
        return slaveTransactionExecutorBeanName;
    }

    public void setSlaveTransactionExecutorBeanName(String slaveTransactionExecutorBeanName) {
        this.slaveTransactionExecutorBeanName = slaveTransactionExecutorBeanName;
    }

    public String getSlaveTransactionManagerBeanName() {
        return slaveTransactionManagerBeanName;
    }

    public void setSlaveTransactionManagerBeanName(String slaveTransactionManagerBeanName) {
        this.slaveTransactionManagerBeanName = slaveTransactionManagerBeanName;
    }

    public String getTransactionExecutorBeanName() {
        return transactionExecutorBeanName;
    }

    public void setTransactionExecutorBeanName(String transactionExecutorBeanName) {
        this.transactionExecutorBeanName = transactionExecutorBeanName;
    }
}
